// 我门可以基于字符串类型 来创建新的类型  模板字符串
// 模板字符串类型 类似es6的模板字符串
// 可以将多个字符串类型进行组装...................................................................................
type name = "jw";
// type handsomeName = `handsome ${name}`; ===> "handsome jw" 就是es6模板字符串，产生的结果是一个字符串类型
type handsomeName = `handsome ${name}`;

// 模板字符串 ，当我们传入一个联合类型时 也有分发机制.......................................................
// 一个联合类型对一个字符串
type Direction1 = "left" | "top" | "right" | "bottom";
type AllMargin = `margin -${Direction1}`; // ==> "margin -left" | "margin -top" | "margin -right" | "margin -bottom"
type AllPadding = `padding -${Direction1}`; // ==> "margin -left" | "margin -top" | "margin -right" | "margin -bottom"
// 一个联合类型对一个联合类型
type MarginOrPading = "padding" | "margin";
type Direction2 = "left" | "top" | "right" | "bottom";
//  "padding-left" | "padding-top" | "padding-right" | "padding-bottom" | "margin-left" | "margin-top" | "margin-right" | "margin-bottom"
type Compose = `${MarginOrPading}-${Direction2}`;

// 可以基于这种方式编写一些 固定的格式的类型 scss变量
// element-plus (red-100 red-200 red-300)
// 商品规格 棕色-20cm  红色-20cm 。。。

// 和泛型进行连用 保证类型T是字符串类型， 否则使用约束更合理 T extends string | number | bigint | boolean | null | undefined...................
//  如果通过的是 & 的方式 保证类型是字符串类型， 否则使用约束更合理
type IColor<S extends string | number | bigint | boolean | null | undefined> =
  `red-${S}`;
// 如果，确定只是传入字符串，可以用下面的形式，传入除string的都会报错
// type IColor<T> = `hello ${T & string}`;

// 可以传入字面量类型 ， 也可以传入基础类型
type I1 = IColor<100>;
type I2 = IColor<null | undefined>;
// 类似于正则，表示传入某种类型
type I3 = IColor<string>;
type I4 = IColor<number>;
// 类似于正则，表示传入某种类型, 可以通过这个方式来描述 对key 的限制
// 所有的基础类型的模板字符串都是自变量类型的父类型(类型要相同)
type I5 = I1 extends I3 ? true : false;

// 将对象的属性进行重命名操作 {name,age,address}; ==>{r_name,r_age,r_address};
const person = {
  name: "jw",
  age: 30,
  address: "abc",
};
// 将对象的属性进行重命名操作 {name,age,address}; ==>{r_name,r_age,r_address};
// 重映射 as  pickObjectByValue
type Person = typeof person; // Person -> {re_name:string,re_age:number,re_address:string}
// as `re_${K & string}`]
type RePerson<T> = {
  // 模板字符串进行重命名操作
  [K in keyof T as `re_${K & string}`]: T[K]; // 模板字符串 + 冲映射可以直接做对象的格式映射
};
type Result = RePerson<Person>;

// 模板字符串有内置的泛型接口，可以支持工具类型
// Capitalize
type A1 = Capitalize<I1>;
type A2 = Uncapitalize<A1>;
type A3 = Uppercase<A1>;
type A4 = Lowercase<A3>;

// 根据对象生成对应的getter方法  vue3  @xxx-> onXxxx   emit('xxx')

// type PersonGetter<T> = {
//   [K in keyof T as `get${Capitalize<K & string>}`]: () => T[K];
// };
// let personGetter!: PersonGetter<Person>;
// let r3 = personGetter.getName();
// let r2 = personGetter.getAge();
// let r1 = personGetter.getAddress();

let person1: Person = { name: "jw", age: 30, address: "北京" };
type WithGetter<T> = {
  [K in keyof T as `get${Capitalize<K & string>}`]: () => T[K];
};
type Compute<T> = { [K in keyof T]: T[K] };
type WithGetterType = Compute<WithGetter<Person>>;
let personGetter1: WithGetterType = {
  getName() {
    return person.name;
  },
  getAge() {
    return person.age;
  },
  getAddress() {
    return person.address;
  },
};

// 模版字符串可以用于 infer 关键字 来使用......................................
//根据模式匹配符来取类型jiang wen
//infer 可以进行位置推断
//可以推断数组|元组|string
// ${infer F}${infer X}=====>jiangwen  F 代表第一个字符串  X代表第一个字符串以后的字段
// ${infer F}a${infer X}=====>jiangwen  F 代表a以前字符串  X代表a以后的字段 a就是分隔符
type GetNameFirstchar<T> = T extends `${infer F}a${infer X}` ? F : never;
type Firstchar = GetNameFirstchar<"jiangwen">; //可以通过infer 来进行字符串的位置推断，符合即可推断(中间可以配置分隔符,用字符串某个字符例如a 空格也可以)

export {};
